package com.gameserver;

import java.io.*;

import org.json.*;

import com.gameserver.Game.GameState;

import java.net.*;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.UUID;

public class GameSocketServer {

	PrintWriter out;
	BufferedReader in;
	ServerSocket serverSocket = null;
	SocketAccepter socketAccepter;
	Thread accepterSocket;
	Socket connection;
	Game currentGame;
	int gameIdx;
	
	PlayerSocketRunnable player1;
	PlayerSocketRunnable player2;
	
	Thread player1Thread;
	Thread player2Thread;
	
	ArrayList<Game> runningGames;
	ArrayList<PlayerSocketRunnable> players;
	
	public GameSocketServer(int portNumber) throws UnknownHostException, SocketException
	{
		gameIdx = 0;
		Enumeration<NetworkInterface> n = NetworkInterface.getNetworkInterfaces();
		InetAddress[] addresses;
		InetAddress addr = null;
		
		for (; n.hasMoreElements();)
	    {
	        NetworkInterface e = n.nextElement();
	        
	        System.out.println(e.getName());

	        Enumeration<InetAddress> a = e.getInetAddresses();
	        for (; a.hasMoreElements();)
	        {
	        	String type = "";
	            InetAddress ad = a.nextElement();
	            
	            if(ad.isAnyLocalAddress())
	            {
	            	type = "AnyLocal";
	            }
	            
	            if(ad.isLinkLocalAddress())
	            {
	            	type = "LinkLocal";
	            }
	            if(ad.isLoopbackAddress())
	            {
	            	type = "Loopback";
	            }
	            if(ad.isMulticastAddress())
	            {
	            	type = "Multicast";
	            }
	            if(ad.isMCGlobal())
	            {
	            	type = "MC Global";
	            }
	            if(ad.isMCLinkLocal())
	            {
	            	type = "MCLinkLocal";
	            }
	            if(ad.isMCNodeLocal())
	            {
	            	type = "MCNodeLocal";
	            }
	            if(ad.isMCOrgLocal())
	            {
	            	type = "MCOrgLocal";
	            }
	            if(ad.isMCSiteLocal())
	            {
	            	type = "MCSiteLocal";
	            }
	            
	           
	            System.out.println("  " + ad.getHostAddress() + "  " + ad.getHostName() + " " + type);
	        }
	    }
		
//		for (int i = 0; i < addresses.length; i++) {
//			if (addresses[i].isMCGlobal()) {
//				addr = addresses[i];
//			}
//		}

		if (true) {
			// Initialize serverSocket
			try {
				serverSocket = new ServerSocket(portNumber, 100, InetAddress.getLocalHost());
				socketAccepter = new SocketAccepter(serverSocket);
				this.accepterSocket  = new Thread(socketAccepter);
				this.accepterSocket.start();
				
				System.out.println("Server initialized on Port: "
						+ serverSocket.getLocalPort() + "\nCurrent IP: "
						+ serverSocket.getInetAddress().getHostAddress());
			} catch (IOException e) {
				e.printStackTrace();

			}
		}
	
		currentGame = newGame();
		runningGames = new ArrayList<Game>();
		runningGames.add(currentGame);
	}
	
	public void getConnection()
	{
		PlayerSocketRunnable runnable;
		Thread thread;
		
		if(this.socketAccepter.hasSocket()){
			connection = this.socketAccepter.getSocket();
			runnable = new PlayerSocketRunnable(connection);
			thread = new Thread(runnable);

			if(player1 == null)
			{
				this.player1 = runnable;
				this.player1Thread = thread;
				this.player1Thread.start();
			}else{
				this.player2 = runnable;
				this.player2Thread = thread;
				this.player2Thread.start();
			}
			System.out.println("Connection Accepted from" + connection.getInetAddress());
		}
		
	}
	
	public void setupStreams() throws IOException
	{
		out = new PrintWriter(
				new OutputStreamWriter(connection.getOutputStream()));
		out.flush();
		in = new BufferedReader(
				new InputStreamReader(connection.getInputStream()));
	}
	
	public void recieveData()
	{
		String messageData = null;
		String message;
		Object tmp;
		JSONObject obj;
		JSONObject otherReply;
		
		int otherPlayer = 0;
		
		if(player1 != null)
		{
			if(player1.message != null){
				messageData = player1.message;
				out = player1.output;
				connection = player1.socket;
				otherPlayer = 2;
				System.out.println("Message Read" + messageData);
				player1.clearMessage();
			}
		} 
			
		if(player2 != null)
		{
			if(player2.message != null){
				messageData = player2.message;
				out = player2.output;
				connection = player2.socket;
				otherPlayer = 1;
				System.out.println("Message Read" + messageData);
				player2.clearMessage();
//				this.player2Thread = new Thread(this.player2);
//				player2Thread.start();
			}
		}
		
//		try {
//			messageData = in.readLine();
//			System.out.println("Message Read" + messageData);
//			
//		} catch (IOException e) {
//			e.printStackTrace();
//		}	
		
		if(messageData != null){
			try{
				
				obj = new JSONObject(messageData);
				System.out.println("Message Valid");
				
				try {
					message = obj.getString("Message");
					System.out.println("Message Type:" + message);
					
					JSONObject reply = new JSONObject();
					
					if(message.compareTo("Initial") == 0)
					{
						acceptInitial();
					}else if(message.compareTo("Turn") == 0)
					{
						System.out.println();
						acceptTurn(obj.getJSONObject("Turn Data"), otherPlayer);
					}else if(message.compareTo("Winner") == 0)
					{
						System.out.println();
						acceptWinner(obj.getJSONObject("Turn Data"), otherPlayer);
					}else{
						System.err.println("Message unrecognized");
					}
					
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}catch(JSONException e){
				e.printStackTrace();
			}
			
			}else{
				if(currentGame.state == GameState.READYPLAYER1)
				{
					
				}
				else if (currentGame.state == GameState.READYPLAYER2)
				{
					
				}
			}
		
	}
	
	public void closeConnections()
	{
		try{
			out.close();
			in.close();
			connection.close();
		}catch (IOException e) {
			e.printStackTrace();
		}	
	}
	
	public Game newGame()
	{
		Game game = new Game(gameIdx);
		gameIdx++;
		return game;
	}
	
	public void sendResponse(JSONObject response)
	{
		out.println(response.toString());
		out.flush();
		System.out.println("Response Sent");
	}
	
	private void acceptInitial() throws JSONException
	{
		JSONObject reply = new JSONObject();
		
		
		if(currentGame.isAccepting)
		{
			reply.put("Message", "Rqst Received");
			currentGame.addPlayer(connection.getInetAddress());
			reply.put("gameId", currentGame.gameID);
			System.out.println("Assigned to Game: " + currentGame.gameID);
			
			if(currentGame.player1 == connection.getInetAddress())
			{
				reply.put("Assignment", 1);
				System.out.println("Assigned Player 1");
			}else if(currentGame.player2 == connection.getInetAddress())
			{
				reply.put("Assignment", 2);
				System.out.println("Assigned Player 2");
			}else{
				reply.put("Assignment", -1);
				System.out.println("Not Assigned");
			}
			
		}else{
			reply.put("Message", "Rqst Denied");
			reply.put("gameId", -1);
			System.out.println("Unable to Assign Current Game is full");
		}
		
		sendResponse(reply);
	}
	
	private void acceptTurn(JSONObject turnData, int otherPlayer) throws JSONException
	{
		JSONObject reply = new JSONObject();
		JSONObject otherReply = new JSONObject();
	
		reply.put("Message", "Turn Recieved");
		otherReply.put("Message", "Turn");
		otherReply.put("Turn Data", turnData);
		
		currentGame.addPlayerTurn(turnData);
		
		sendResponse(reply);
		
		if(otherPlayer == 1)
		{
			player1.output.println(otherReply.toString());
			player1.output.flush();
		}else if (otherPlayer == 2)
		{
			player2.output.println(otherReply.toString());
			player2.output.flush();
		}
	}
	
	private void sendTurn() throws JSONException
	{
		JSONObject reply = new JSONObject();
		reply.put("Message", "Turn");
		reply.put("Turn", currentGame.getPlayerTurn());
		sendResponse(reply);
	}
	
	private void acceptWinner(JSONObject turnData, int otherPlayer) throws JSONException
	{
		JSONObject reply = new JSONObject();
		reply.put("Message", "Winner Received");
		
		sendResponse(reply);
	}
	
	private void sendWinner() throws JSONException
	{
		JSONObject reply = new JSONObject();
		reply.put("Message", "Win");
		
		reply.put("Turn", currentGame.getPlayerTurn());
		
		sendResponse(reply);
	}
	
	private JSONObject stringToJSONObject(String jsonString) throws JSONException
	{
		JSONObject obj = new JSONObject(jsonString);
		return obj;
	}
}
